﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using TjZheng.Framework;

namespace TjZheng.Controls
{
    /// <summary>
    /// 查询条件组织（MySql参数化查询）
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public class QueryMySqlFilter : QueryFilter
    {        /// <summary>
        /// 构造函数
        /// </summary>
        public QueryMySqlFilter()
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="Param">字段条件组织，如Name组织 Name=Request[Name]</param>
        public QueryMySqlFilter(string Param)
            : base(Param)
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="Params">字段条件批量组织，如Name,Code组织 Name=Request[Name] AND Code=Request[Code]</param>
        public QueryMySqlFilter(List<string> Params)
            : base(Params)
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="Param">字段条件组织，如Name组织 Name=Request[Name]</param>
        /// <param name="OtherConditions">手动组织条件，如Name=具体值</param>
        public QueryMySqlFilter(string Param, string OtherConditions)
            : base(Param, OtherConditions)
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="Params">字段条件组织，如Name组织 Name=Request[Name]</param>
        /// <param name="OtherConditions">手动组织条件，如Name=具体值</param>
        public QueryMySqlFilter(List<string> Params, string OtherConditions)
            : base(Params, OtherConditions)
        {
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            var objValueProvider = filterContext.Controller.ValueProvider;
            var objController = filterContext.Controller as Controller;
            List<QueryParameterEntity> objQueryParameterEntitys = new List<QueryParameterEntity>();
            if (Param.IsNoNull())
            {
                string objParamValue = filterContext.HttpContext.Request[Param].FilterSql();
                if (objParamValue.IsNoNull())
                {
                    objQueryParameterEntitys.Add(new QueryParameterEntity { Field = Param, Value = objParamValue });
                }
            }
            if (Params.IsNoNull())
            {
                foreach (var objParam in Params)
                {
                    string objParamValue = filterContext.HttpContext.Request[objParam].FilterSql();
                    if (objParamValue.IsNoNull())
                    {
                        objQueryParameterEntitys.Add(new QueryParameterEntity { Field = Param, Value = objParamValue });
                    }
                }
            }
            List<string> QueryConditionList = new List<string>();
            QueryResult objQueryResult = null;
            if (!objValueProvider.ContainsPrefix("QueryInfo.Prefixs"))
            {
                objQueryResult = ProcessQueryResult(objQueryParameterEntitys, QueryConditionList, null);
                filterContext.Controller.ViewBag.QueryResult = objQueryResult;
                return;
            }
            var objValueProviderResult = objValueProvider.GetValue("QueryInfo.Prefixs");
            if (objValueProviderResult == null)
            {
                objValueProviderResult = objValueProvider.GetValue("QueryInfo.Prefixs[]");
                if (objValueProviderResult == null)
                {
                    objQueryResult = ProcessQueryResult(objQueryParameterEntitys, QueryConditionList, null);
                    filterContext.Controller.ViewBag.QueryResult = objQueryResult;
                    return;
                }
            }
            List<QueryInfo> QueryInfoList = new List<QueryInfo>();
            foreach (var prefix in objValueProviderResult.RawValue as string[])
            {
                if (objValueProvider.ContainsPrefix(prefix))
                {
                    QueryInfo objQueryInfo = new QueryInfo() { Prefix = prefix };
                    objQueryInfo.SetQueryCondition(DataBaseType.MySql);
                    //Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, null, null);
                    IModelBinder objModelBinder = ModelBinders.Binders.GetBinder(typeof(QueryInfo));
                    ModelBindingContext objModelBindingContext = new ModelBindingContext()
                    {
                        ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => objQueryInfo, typeof(QueryInfo)),
                        ModelName = prefix,
                        ModelState = objController.ModelState,
                        //PropertyFilter = propertyFilter,
                        ValueProvider = objValueProvider
                    };
                    objModelBinder.BindModel(objController.ControllerContext, objModelBindingContext);
                    if (objController.ModelState.IsValid)
                    {
                        objQueryInfo.QueryValue = objQueryInfo.QueryValue.FilterSql();
                        QueryInfoList.Add(objQueryInfo);
                        if (objQueryInfo.QueryValue.IsNoNull())
                        {
                            objQueryParameterEntitys.Add(new QueryParameterEntity { Field = objQueryInfo.QueryField, Value = objQueryInfo.QueryValue, IsQueryInfo = true, QueryPrefix = objQueryInfo.Prefix });
                        }
                    }
                }
            }
            objQueryResult = ProcessQueryResult(objQueryParameterEntitys, QueryConditionList, QueryInfoList);
            objQueryResult.QueryInfos = QueryInfoList;
            filterContext.Controller.ViewBag.QueryResult = objQueryResult;
        }

        QueryResult ProcessQueryResult(List<QueryParameterEntity> objQueryParameterEntitys, List<string> QueryConditionList, List<QueryInfo> QueryInfoList)
        {
            objQueryParameterEntitys = objQueryParameterEntitys.Select((c, i) => { c.ParameterName = string.Format("{0}{1}", c.Field, i); return c; }).ToList();
            var objNotQuerys = objQueryParameterEntitys.Where(c => !c.IsQueryInfo).ToList();
            if (objNotQuerys.IsNoNull())
            {
                QueryConditionList.AddRange(objNotQuerys.Select(c => string.Format("{0}=?{1}", c.Field, c.ParameterName)));
            }
            QueryResult objQueryResult = new QueryResult();
            if (OtherConditions.IsNoNull())
            {
                QueryConditionList.Add(OtherConditions);
            }
            var objQuerys = objQueryParameterEntitys.Where(c => c.IsQueryInfo).ToList();
            if (QueryInfoList.IsNull() || objQuerys.IsNull())
            {
                if (QueryConditionList.IsNoNull())
                {
                    objQueryResult.Condition = QueryConditionList.Aggregate((x, y) => x + " AND " + y);
                }
                objQueryResult.Parameters = objNotQuerys.Select(c => c.ParameterName).JoinString(",").CreateParameters(DataBaseType.MySql, objNotQuerys.Select(c => c.Value).ToArray());
                return objQueryResult;
            }
            foreach (var objQuery in objQuerys)
            {
                var objQueryInfo = QueryInfoList.First(c => c.Prefix == objQuery.QueryPrefix);
                QueryConditionList.Add(objQueryInfo.GetConditionWithParameter(objQuery.ParameterName));
                objQuery.Value = objQueryInfo.GetParameterValue();
            }
            if (QueryConditionList.IsNoNull())
            {
                objQueryResult.Condition = QueryConditionList.Aggregate((x, y) => x + " AND " + y);
                List<DbParameter> objDbParameters = new List<DbParameter>();
                var objNotQueryParameters = objNotQuerys.Select(c => c.ParameterName).JoinString(",").CreateParameters(DataBaseType.MySql, objNotQuerys.Select(c => c.Value).ToArray());
                if (objNotQueryParameters.IsNoNull())
                {
                    objDbParameters.AddRange(objNotQueryParameters);
                }
                var objQueryParameters = objQuerys.Select(c => c.ParameterName).JoinString(",").CreateParameters(DataBaseType.MySql, objQuerys.Select(c => c.Value).ToArray());
                if (objQueryParameters.IsNoNull())
                {
                    objDbParameters.AddRange(objQueryParameters);
                }
                objQueryResult.Parameters = objDbParameters.ToArray();
            }
            return objQueryResult;
        }
    }
}
